package com.wsh.security.rest;

import cn.hutool.core.util.IdUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import com.wf.captcha.ArithmeticCaptcha;
import com.wsh.annotation.AnonymousAccess;
import com.wsh.entity.sys.UserEntity;
import com.wsh.security.config.SecurityProperties;
import com.wsh.security.security.TokenProvider;
import com.wsh.security.service.OnlineUserService;
import com.wsh.sys.UserService;
import com.wsh.utils.JsonResult;
import com.wsh.utils.RedisUtils;
import com.wsh.utils.SecurityUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @date 2018-11-23
 * 授权、根据token获取用户详细信息
 */
@Slf4j
@RestController
@RequestMapping("/auth")
@Api(tags = "系统：系统授权接口")
public class AuthController {

    @Value("${loginCode.openCode:false}")
    private Boolean openCode;

    @Value("${loginCode.expiration}")
    private Long expiration;

    @Value("${rsa.private_key}")
    private String privateKey;

    @Value("${loginkit.singleLogin}")
    private Boolean singleLogin;

    @Autowired
    private UserService userService;

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private OnlineUserService onlineUserService;

    @Autowired
    private TokenProvider tokenProvider;

    private final SecurityProperties properties;

    private final AuthenticationManagerBuilder authenticationManagerBuilder;

    public AuthController(SecurityProperties properties, AuthenticationManagerBuilder authenticationManagerBuilder) {
        this.properties = properties;
        this.authenticationManagerBuilder = authenticationManagerBuilder;
    }

    @ApiOperation("登录授权")
    @AnonymousAccess
    @PostMapping(value = "/login")
    public Object login(UserEntity userEntity, HttpServletRequest request){
        // 密码解密
        RSA rsa = new RSA(privateKey, null);
        String password = new String(rsa.decrypt(userEntity.getPassword(), KeyType.PrivateKey));
        // 查询验证码
        String code = (String) redisUtils.get(userEntity.getUuid());
        // 清除验证码
        redisUtils.del(userEntity.getUuid());

        // 开发环境不进行验证码校验
        if (openCode) {
            if (StringUtils.isBlank(code)) {
                return JsonResult.fail("验证码不存在或已过期");
            }

            if (StringUtils.isBlank(userEntity.getCode()) || !userEntity.getCode().equalsIgnoreCase(code)) {
                return JsonResult.fail("验证码错误");
            }
        }

        UsernamePasswordAuthenticationToken authenticationToken =
                new UsernamePasswordAuthenticationToken(userEntity.getUsername(), password);

        Authentication authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken);
        SecurityContextHolder.getContext().setAuthentication(authentication);
        // 生成令牌
        String token = tokenProvider.createToken(authentication);
        final User user = (User) authentication.getPrincipal();

        // 保存在线信息
        onlineUserService.save(user, token, request);

        if(singleLogin){
            //踢掉之前已经登录的token
            onlineUserService.checkLoginOnUser(userEntity.getUsername(),token);
        }

        Map resultData = new HashMap();
        // 返回 token 与 用户信息
        resultData.put("token", properties.getTokenStartWith() + token);
//        resultData.put("data", user);
        return JsonResult.success(resultData);
    }

    /**
     * 根据token查询用户
     */
    @ApiOperation("获取用户信息")
    @GetMapping("/getUserInfo")
    public Object getUserInfo() {
        String userName = SecurityUtils.getUsername();
        return JsonResult.success(userService.findByUserName(userName, false));
    }

    @AnonymousAccess
    @ApiOperation("获取验证码")
    @GetMapping(value = "/code")
    public ResponseEntity<Object> getCode(UserEntity userEntity){
        // 算术类型 https://gitee.com/whvse/EasyCaptcha
        ArithmeticCaptcha captcha = new ArithmeticCaptcha(111, 36);
        // 几位数运算，默认是两位
        captcha.setLen(2);
        // 获取运算的结果
        String result = captcha.text();
        String code_uuid = properties.getCodeKey() + IdUtil.simpleUUID();
        // 保存
        redisUtils.set(code_uuid, result, expiration, TimeUnit.MINUTES);
        // 验证码信息
        Map<String,Object> imgResult = new HashMap<String,Object>(2){{
            put("img", captcha.toBase64());
            put("uuid", code_uuid);
        }};
        // 清空验证码（频繁刷新，缓存清空）
        String uuid = userEntity.getUuid();
        if (StringUtils.isNotBlank(uuid)) {
            redisUtils.del(uuid);
        }
        return ResponseEntity.ok(imgResult);
    }

    @ApiOperation("退出登录")
    @AnonymousAccess
    @PostMapping(value = "/logout")
    public ResponseEntity<Object> logout(HttpServletRequest request){
        String token = tokenProvider.getToken(request);
        onlineUserService.logout(token);
        redisUtils.del("logout" + token);
        return new ResponseEntity<>(HttpStatus.OK);
    }
}
